package de.pass.ch.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import de.pass.ch.pt.IStreetProfile;
import de.pass.ch.pt.StreetProfile;
import de.pass.ch.pt.StreetType;

public class Util {

	/**
	 * Deserialisiert ein Integer-Array aus dem gegebenen File und gibt dieses
	 * zurueck. Das Integer-Array muss im File vorher ueber einen
	 * ObjectOutputStream serialisiert worden sein.
	 * 
	 * @param file
	 *            - File, in dem das Integer-Array serialisiert ist.
	 * @return Integer-Array
	 */
	public static int[] deserializeIntArray(String file) {

		ObjectInputStream in = null;
		int[] res = null;

		try {

			long start = System.currentTimeMillis();

			in = new ObjectInputStream(new FileInputStream(file));
			res = (int[]) in.readObject();

			System.out.println("deserializing array took "
					+ (System.currentTimeMillis() - start) + " ms");

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null)
					in.close();
			} catch (Exception e) {
			}
		}

		assert (res != null) : "Fehler beim Einlesen eines Integer-Arrays";

		return res;

	}

	/**
	 * Serialisiert das gegebene Integer-Array ueber einen ObjectOutputStream in
	 * das gegebene File.
	 * 
	 * @param file
	 *            - File, in das das Integer-Array serialisiert werden soll
	 * @param array
	 *            - Array, das serialisiert werden soll
	 */
	public static void serializeIntArray(String file, int[] array) {

		ObjectOutputStream out = null;

		try {

			long start = System.currentTimeMillis();

			out = new ObjectOutputStream(new FileOutputStream(file));
			out.writeObject(array);

			System.out.println("serializing array took "
					+ (System.currentTimeMillis() - start) + " ms");

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
			} catch (Exception e) {
			}
		}

	}

	/**
	 * Gibt die fuer die gegebene Kante benoetigte Dauer in Abhaengigkeit des
	 * gegebenen Strassenprofils zurueck.
	 * 
	 * @param meter
	 *            - Kantengewicht in Meter
	 * @param type
	 *            - Strassentyp der Kante
	 * @param factor
	 *            - Faktor der Kante
	 * @param streetProfile
	 *            - Strassenprofil
	 * @return benoetigte Dauer fuer die Kante in Sekunden
	 */
	public static int calculateDuration(int meter, short type, short factor,
			IStreetProfile streetProfile) {
		float FAKK, KMSTUNDE;

		short nTempo = 0;

		if (factor == 0)
			factor = 100;

		if (type == 100) {// FUSSGAENGERZONE
			nTempo = streetProfile.getSpeedPedestrianArea();
		} else if (type == 200) {// FELDWEG
			nTempo = streetProfile.getSpeedCountrylane();
		} else if (type == StreetType.STADTSTRASSE.getValue()
				+ StreetType.KREISSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedCountryRoadTown();
		} else if (type == StreetType.STADTSTRASSE.getValue()
				+ StreetType.LANDSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedCountryRoadTown();
		} else if (type == StreetType.STADTSTRASSE.getValue()
				+ StreetType.BUNDESSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedFederalRoadTown();
		} else if (type == StreetType.STADTSTRASSE.getValue()
				+ StreetType.AUTOBAHN.getValue()) {
			nTempo = streetProfile.getSpeedHighwayTown();
		} else if (type == StreetType.STADTSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedTownRoad();
		} else if (type == StreetType.KREISSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedRegionalRoad();
		} else if (type == StreetType.LANDSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedCountryRoad();
		} else if (type == StreetType.BUNDESSTRASSE.getValue()) {
			nTempo = streetProfile.getSpeedFederalRoad();
		} else if (type == StreetType.AUTOBAHN.getValue()) {
			nTempo = streetProfile.getSpeedHighway();
		} else {
			nTempo = 50;
		}
		if (nTempo == 0) {
			return 1;
		}

		// Berechnung der Geschwindigkeit mit Wetterfaktor und Tempofaktor
		// 600 ( 60*10 ) Wert liegt in Stunden ([h]=[km]/[km/h] vor
		// -> 60 Std->Min., 10->Min.->10-tel Min.

		if (streetProfile.getStreetFactorMode()) {
			FAKK = (float) (factor * 0.01);
			if (FAKK == 0.0 || FAKK > 1.0)
				FAKK = (float) 1.0;
		} else {
			FAKK = (float) 1.0;
		}
		KMSTUNDE = nTempo * FAKK;
		if (KMSTUNDE == 0.0)
			return (1);

		double helpResult = ((3600 * meter / KMSTUNDE) / 1000);
		int result = (int) helpResult;
		if (result <= 0)
			result = 1;
		return result;
	}

	public static void main(String[] args) {
		System.out.println(calculateDuration(1538, (short) 1, (short) 90,
				StreetProfile.getInstance(StreetProfile.DEFAULT_PROFILE)));
	}

	/**
	 * Konvertiert das angegebene Array von Bytes (Länge 4) in ein Integer.
	 * Hierbei wird die ByteOrder "Little Endian" verwendet.
	 * 
	 * @param bytes
	 *            - zu konvertierende Bytes
	 * @return Integer-Wert der gegebenen Bytes
	 */
	public static int convertToInt(byte[] bytes) {
		ByteBuffer byteBuffer = ByteBuffer.allocate(4);
		byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
		byteBuffer.put(bytes);
		return byteBuffer.getInt(0);
	}

	/**
	 * Konvertiert das angegebene Array von Bytes (Länge 2) in ein Short.
	 * Hierbei wird die ByteOrder "Big Endian" verwendet.
	 * 
	 * @param bytes
	 *            - zu konvertierende Bytes
	 * @return Short-Wert der gegebenen Bytes
	 */
	public static short convertToShort(byte[] bytes) {
		ByteBuffer byteBuffer = ByteBuffer.allocate(2);
		byteBuffer.order(ByteOrder.BIG_ENDIAN);
		byteBuffer.put(bytes);
		return byteBuffer.getShort(0);
	}

}
